package com.kstudio.videocapture.z;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.media.MediaMetadataRetriever;
import android.os.AsyncTask;

import com.kstudio.videocapture.listfile.KFileListItem;
import com.kstudio.videocapture.util.KException;
import com.kstudio.videocapture.util.KLog;
import com.kstudio.videocapture.util.KUtil;

public class KFileListAsync {
    private final KLog log = new KLog("KVideoCaptureAsync");

    public static final int COMMAND_GET_LIST_FRAME  = 0x00001;
    public static final int COMMAND_GET_IMAGE_FRAME = 0x00002;
    public static final int COMMAND_SAVE_FRAME      = 0x00003;

    public static final int RESULT_OK = 0x0001;
    public static final int RESULT_CANCEL = 0x0002;

    private static final int STATE_READY         = 0x1001;
    private static final int STATE_RUNNING       = 0x1002;
    private static final int STATE_PAUSE         = 0x1003;

    private CaptureTask             mAsyncTask;
    private Param                   mParam;
    private KVideoCaptureListener   mListener;

    private int mState;

    public interface KVideoCaptureListener {
        void onProgressUpdate();
        void onProgressUpdate(String path, Bitmap b);
        void onResult(int result);
    }

    public KFileListAsync(KVideoCaptureListener l) {
        mAsyncTask = null;
        mListener = l;
        mParam = null;

        mState = STATE_READY;
    }


    /* Public Function */
    public void start(int command, ArrayList<?> list, int width, int height) {
        if(mState == STATE_READY || mState == STATE_PAUSE) {
            mParam     = new Param(command, list, width, height);
            mAsyncTask = new CaptureTask();
            mAsyncTask.execute(mParam);
        }
    }

    public void start(int command, String in, String out, int[] time) {
        if(mState == STATE_READY || mState == STATE_PAUSE) {
            mParam     = new Param(command, in, out, time);
            mAsyncTask = new CaptureTask();
            mAsyncTask.execute(mParam);
        }
    }

    public void pause() {
        if(mState == STATE_RUNNING) {
            if(!mAsyncTask.isCancelled()) {
                mAsyncTask.cancel(false);
            }
            mAsyncTask.Stop();
            mState = STATE_PAUSE;
        }
    }

    public void resume() {
        if(mState == STATE_PAUSE) {
            mAsyncTask = new CaptureTask();
            mAsyncTask.execute(mParam);
            mState = STATE_READY;
        }
    }

    public void stop() {
        if(mState == STATE_RUNNING) {
            mAsyncTask.Stop();
            mState = STATE_READY;
        } else if(mState == STATE_PAUSE) {
            mState = STATE_READY;
        }
    }

    /* Private Function */
    private String saveFile(Bitmap b, String out, String name, int timeUS) throws KException {
        FileOutputStream outStream = null;

        String outPath = null;
        String outName = name.substring(0, name.lastIndexOf(".")-1);

        String tmpPath;
        int i = 0;
        File dir = new File(out);

        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                KException e = new KException(KException.WARRING_KVideoCaptureAsync_1, "Save directory is not create");
                throw e;
            }
        }

        int timeUSToSec = timeUS / 1000;
        outPath = String.format("%s%s_%02d_%02d_%02d.png", out, outName, timeUSToSec/3600, (timeUSToSec%3600)/60, timeUSToSec%60);
        log.d("1 outPath %s",outPath);

        File outFile = new File(outPath);
        while(outFile.exists()) {
            i++;
            if(i == 1) {
                tmpPath = outPath.substring(0, outPath.lastIndexOf("."));
            } else {
                tmpPath = outPath.substring(0, outPath.lastIndexOf(".")-4);
            }
            outPath = String.format("%s_%03d.png", tmpPath, i);
            log.i("outPath %s",outPath);
            outFile = new File(outPath);
        }

        try {
            outStream = new FileOutputStream(outFile);
            if ( b.compress(CompressFormat.PNG, 100, outStream) );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
             try {
                 outStream.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
        }

        return outPath;
    }

    private class Param {
        private int mCommand;

        private ArrayList<?> mArrayList;
        private int mWidth;
        private int mHeight;

        private String mInPath;
        private String mOutPath;
        private int[]  mTime;

        Param(int command, ArrayList<?> list, int width, int height) {
            mCommand   = command;
            mArrayList = list;
            mWidth     = width;
            mHeight    = height;
        }

        Param(int command, String in, String out, int[] time) {
            mCommand = command;
            mInPath  = in;
            mOutPath = out;
            mTime  = time;
        }

        public int getCommand() { return mCommand; }

        public ArrayList<?> getArray()   { return mArrayList; }
        public int          getWidth()   { return mWidth; }
        public int          getHeight()  { return mHeight; }

        public String       getInPath()  { return mInPath; }
        public String       getOutPath() { return mOutPath; }
        public int[]        getTime()  { return mTime; }
    }

    private class Progress {
        private int mCommand;
        private Bitmap bitmap;
        private String filePath;

        Progress(int command, Bitmap b, String path) {
            mCommand = command;
            bitmap = b;
            filePath = path;
        }

        public int      getCommand()    { return mCommand; }
        public Bitmap   getBitmap()     { return bitmap; }
        public String   getPath()       { return filePath; }
    }

    private class CaptureTask extends AsyncTask<Param, Progress, Void> {
        private boolean Running;

        private CaptureTask() {
            super();
        }

        private void Stop() {
            Running = false;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            Running = true;
            mState = STATE_RUNNING;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            mListener.onResult(RESULT_OK);
            mState = STATE_READY;
        }

        @Override
        protected void onCancelled(Void result) {
            super.onCancelled(result);

            mListener.onResult(RESULT_CANCEL);
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected void onProgressUpdate(Progress... values) {
            super.onProgressUpdate(values);
            log.e("values = "+values);
            log.e("values[0] = "+values.length);
            if(values.length > 0) {
                for(int i = 0; i < values.length; i++) {
                    if(values[i].getCommand() == COMMAND_SAVE_FRAME) {
                        if(mListener != null) mListener.onProgressUpdate(values[i].getPath(), values[i].getBitmap());
                    }
                }
            }else {
                if(mListener != null) mListener.onProgressUpdate();
            }
        }

        @Override
        protected Void doInBackground(Param... arg0) {

            switch(arg0[0].getCommand()) {
                case COMMAND_GET_LIST_FRAME : {
                    ArrayList<?> list = arg0[0].getArray();
                    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                    KFileListItem fileData = null;
                    Bitmap frame;
                    Bitmap bitmap;
                    int frameWidth = arg0[0].getWidth();
                    int frameHeight = arg0[0].getHeight();

                    for(int i = 0; i < list.size() && Running; i++) {
                        fileData = (KFileListItem) list.get(i);
                        if(fileData.getFileType() == KFileListItem.VIDEO /*&& fileData.getBitmap() == null*/) {
                            retriever.setDataSource(fileData.getPath());
                            frame = retriever.getFrameAtTime();
                            if(frame != null) {
                                bitmap = KUtil.resizedBitmapOnRatio(frame, frameWidth, frameHeight);
                                frame.recycle();

//                                fileData.setBitmap(bitmap);
                            }
                            if(/*fileData.getBitmap() == null*/true) {
//                                fileData.setBitmap(null);
                                fileData.setFileType(KFileListItem.FILE);
                            } else {
                                fileData.setDuration(Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)));
                            }

                            publishProgress();
                        } else if(fileData.getFileType() == KFileListItem.PICTURE /*&& fileData.getBitmap() == null*/) {
                            bitmap = KUtil.fastLoadBitmapResizedOnRatio(fileData.getPath(), frameWidth, frameHeight);
                            if(bitmap != null) {
//                                fileData.setBitmap(bitmap);
                            }

                            publishProgress();
                        }
                    }
                }
                break;

//                case COMMAND_GET_IMAGE_FRAME : {
//                    ArrayList<?> list = arg0[0].getArray();
//                    KImageEditItem fileData = null;
//                    Bitmap bitmap;
//                    int bitmapWidth = arg0[0].getWidth();
//                    int bitmapHeight = arg0[0].getHeight();
//
//                    for(int i = 0; i < list.size() && Running; i++) {
//                        fileData = (KImageEditItem) list.get(i);
//                        if(fileData.getBitmap() == null) {
//                            bitmap = KUtil.fastLoadBitmapResizedOnRatio(fileData.getPath(), bitmapWidth, bitmapHeight);
//                            if(bitmap != null) {
//                                fileData.setBitmap(bitmap);
//                            }
//
//                            publishProgress();
//                        }
//                    }
//                }
//                break;

                case COMMAND_SAVE_FRAME : {
                    Progress progress;
                    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                    File file = new File(arg0[0].getInPath());
                    retriever.setDataSource(file.getPath());

                    int[] time = arg0[0].getTime();
                    int timeUS;

                    for(int i = 0; i < time.length && Running; i++) {
                        timeUS = time[i] * 1000;
                        Bitmap bitmap = retriever.getFrameAtTime(timeUS);
                        String filePath = null;

                        try {
                            filePath = saveFile(bitmap, arg0[0].getOutPath(), file.getName(), timeUS);

                            progress = new Progress(COMMAND_SAVE_FRAME, bitmap, filePath);

                            publishProgress(progress);
                        } catch (KException e) {
                            e.printStackTrace();
                        }
                    }
                }
                default:
                    log.e("doInBackground : Error Command %d",arg0[0].getCommand());
                break;
            }

            return null;
        }
    }
}
